package gov.fgn.sijyp.general.util;

import gov.fgn.siijt.data.IDocumentoEntity;
import gov.fgn.sijyp.bienes.data.BienAlbumFotograficoFoto;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.ResourceBundle;

import javax.el.ELContext;
import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

import org.richfaces.component.UIDataTable;

/**
 * Clase creada para contener funciones genéricas para el uso de los
 * managed beans
 * 
 * @author fabio.navarrete
 */
public class ManagedBeanUtils {

  private static final Properties propertieEntrega = null;
  
  /**
   * Método que retorna el recurso encargado de manejar los mensajes
   * de la aplicación
   * 
   * @return
   * @author fabio.navarrete
   */
  public static final ResourceBundle getMessagesBundle() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    /*
     * String messageBundleName = facesContext.getApplication()
     * .getMessageBundle();
     */
    return facesContext.getApplication().getResourceBundle(facesContext, "msg");
  }

  public static final Properties getEntregaBienesBundle() {

    if (propertieEntrega != null) {
      return propertieEntrega;
    }

    URL url = Thread.currentThread().getContextClassLoader()
                    .getResource("EntregaBienes.properties");
    Properties props = new Properties();

    if (url != null) {
      try {
        InputStream in = url.openStream();
        props.load(in);
      } catch (IOException ioe) {
      }
    }
    return props;
  }

  public static final void descargarBienDocumento(IDocumentoEntity bienDocumento) {

    byte[] data = bienDocumento.getArchivo();
    descargarArchivo(bienDocumento.getLongitud().toString(), bienDocumento.getNombre(), data);
  }

  public static final void descargarBienAlbumFoto(BienAlbumFotograficoFoto foto) {

    descargarArchivo(Integer.toString(foto.getArchivo().length), foto.getNombre(),
                     foto.getArchivo());

  }

  private static final void descargarArchivo(String longitud, String nombreArchivo, byte[] archivo) {

    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    externalContext.setResponseHeader("Content-Type", "application/force-download");
    externalContext.setResponseHeader("Content-Length", longitud);
    externalContext.setResponseHeader("Content-Disposition", "attachment;filename=\""
                                                             + nombreArchivo + "\"");
    try {
      externalContext.getResponseOutputStream().write(archivo);
    } catch (IOException e) {
      e.printStackTrace();
      FacesMessage fm = new FacesMessage(
                                         FacesMessage.SEVERITY_ERROR,
                                         ManagedBeanUtils.getMessagesBundle()
                                                         .getString("general.errorAlDescargarArchivo"),
                                         null);
      FacesContext.getCurrentInstance().addMessage(null, fm);
    }
    facesContext.responseComplete();

  }

  /**
   * TODO:COMENTAR
   * 
   * @param c
   * @param id
   * @param listUI
   * @return
   */
  public static final UIComponent findComponent(UIComponent c, String id, List<UIComponent> listUI) {
    if (id.equals(c.getId())) {
      return c;
    }
    Iterator<UIComponent> kids = c.getFacetsAndChildren();
    while (kids.hasNext()) {
      UIComponent found = findComponent(kids.next(), id, listUI);
      if (found != null) {
        listUI.add(found);
      }
    }
    return null;
  }

  /**
   * Retorna el valor date correspondiente al comienzo de día para la
   * fecha ingresada como parámetro
   * 
   * @param date
   * @return
   * @author fabio.navarrete
   */
  public static Date getStartOfDay(Date date) {
    return clearTime(date);
  }

  /**
   * Retorna la fecha con los valores inferiores al día puestos en
   * ceros
   * 
   * @param date
   * @return
   * @author fabio.navarrete
   */
  public static Date clearTime(Date date) {
    if (date == null) {
      return null;
    }
    Calendar c = Calendar.getInstance();
    c.setTime(date);
    c.set(Calendar.HOUR_OF_DAY, 0);
    c.set(Calendar.MINUTE, 0);
    c.set(Calendar.SECOND, 0);
    c.set(Calendar.MILLISECOND, 0);
    return c.getTime();
  }

  /**
   * Retorna el valor date correspondiente al final del día para la
   * fecha ingresada como parámetro
   * 
   * @param date
   * @return
   * @author fabio.navarrete
   */
  public static Date getEndOfDay(Date date) {
    if (date == null) {
      return null;
    }
    Calendar c = Calendar.getInstance();
    c.setTime(date);
    c.set(Calendar.HOUR_OF_DAY, 23);
    c.set(Calendar.MINUTE, 59);
    c.set(Calendar.SECOND, 59);
    c.set(Calendar.MILLISECOND, 999);
    return c.getTime();
  }

  /**
   * Agrega el mensaje de requerido para el componente con el id
   * especificado como parámetro
   * 
   * @param componentId
   * @author fabio.navarrete
   */
  public static void addRequiredMessageToComponent(String componentId) {
    ManagedBeanUtils.addMessageToComponent(componentId,
                                           ManagedBeanUtils.getMessagesBundle()
                                                           .getString("general.requerido"));
  }

  /**
   * Agrega el mensaje ingresado como parámetro al componente con el
   * id ingresado también como parámetro. El mensaje se agrega como un
   * mensaje de error
   * 
   * @param componentId
   *          Identificador JSF del componente al cual se le
   *          adicionará el mensaje de error
   * @param message
   *          Cadena de texto a poner como mensaje para el componente
   * @author fabio.navarrete
   */
  public static void addMessageToComponent(String componentId, String message) {
    FacesContext context = FacesContext.getCurrentInstance();
    UIViewRoot root = context.getViewRoot();

    List<UIComponent> listUI = new ArrayList<UIComponent>();
    ManagedBeanUtils.findComponent(root, componentId, listUI);

    for (UIComponent uiComponent : listUI) {
      FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message);
      FacesContext.getCurrentInstance().addMessage(uiComponent.getClientId(context), fm);
    }
  }

  /**
   * @param templateString
   * @param values
   * @return
   * @author fabio.navarrete
   */
  public static final String replaceValuesIntoString(String templateString,
      Map<String, String> values) {
    for (Entry<String, String> e : values.entrySet()) {
      templateString = templateString.replaceAll("\\[" + e.getKey() + "\\]", e.getValue());
    }
    return templateString;
  }
  
  public static void validarCantidadResultados(UIDataTable tabla){
		if(null != tabla){
			if (tabla.getRowCount() == 0) {
				FacesContext.getCurrentInstance().addMessage(
						null,
						new FacesMessage(FacesMessage.SEVERITY_INFO,
								ManagedBeanUtils.getMessagesBundle().getString(
										"exhumaciones.diligencia.resultado.vacio"),
								null));
			}
		}
	}
  
  /**
   * 
   * @param facesContext
 * @param idComponent 
   */
  public static void limpiarCombos(FacesContext facesContext, String idComponent) {
		HtmlSelectOneMenu combo = (HtmlSelectOneMenu) findComponent(facesContext, idComponent);
		combo.setValue(null);
		
	}
	
	
	/**
	 * Método principal para busqueda de in componente dado su id, toma el
	 * facesContext y extrae la raiz del árbol
	 * 
	 * @param facesContext
	 * @param id
	 * @return UIComponent
	 */
	private static UIComponent findComponent(FacesContext facesContext, String id) {

		UIComponent result = null;
		UIComponent root = facesContext.getViewRoot();
		if (root != null) {
			result = findComponent(root, id);
		}
		return result;

	}

	/**
	 * Método recursivo para buscar un componente dentro del árbol de
	 * componentes dado su id
	 * 
	 * @param root
	 * @param id
	 * @return UIComponent
	 */
	private static UIComponent findComponent(UIComponent root, String id) {

		UIComponent result = null;
		if (root.getId().equals(id))
			return root;

		for (UIComponent child : root.getChildren()) {
			if (child.getId().equals(id)) {
				result = child;
				break;
			}
			result = findComponent(child, id);
			if (result != null)
				break;
		}
		return result;
	}
	
	public static Object getManagedBean(final String beanName) {
	    FacesContext fc = FacesContext.getCurrentInstance();
	    Object bean;	    
	    try {
	        ELContext elContext = fc.getELContext();
	        bean = elContext.getELResolver().getValue(elContext, null, beanName);
	    } catch (RuntimeException e) {
	        throw new FacesException(e.getMessage(), e);
	    }

	    if (bean == null) {
	        throw new FacesException("Managed bean with name '" + beanName
	            + "' was not found. Check your faces-config.xml or @ManagedBean annotation.");
	    }

	    return bean;
	}
  
}
